using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace UFrame
{
    /// <summary>
    /// 专门作为 MinCS测试窗口
    /// MinCS失败之后, 写一个简易的动态修改字段 调用方法的方式
    /// </summary>
    public class TestInspectorNodeWindow : BaseTestWindow
    {
        [MenuItem("Plateface/UFrameCode/代码快捷调用窗口")]
        static void ShowEditor()
        {
            TestInspectorNodeWindow editor = GetWindow<TestInspectorNodeWindow>();
            editor.titleContent = new GUIContent("盘子脸终端机");
            editor.Show(true);
        }

        private string code = string.Empty;
        private bool isIgnoreCase = false;
        private EModel model = EModel.ShortModify;
        private int selectMethod = 0;

        private string[] filtrationMethod = new[]
            {"Start", "Update", "OnEnable", "OnDestroy", "Finalize", "GetType", "MemberwiseClone"};


        public void OnGUI()
        {
            MinCSRef.isIgnoreCase = EditorGUILayout.Toggle("忽略大小写:", isIgnoreCase);
            code = EditorGUILayout.TextField(code, GUILayout.Height(60));

            if (GUILayout.Button("在组件中执行", GUILayout.Height(30)))
            {
                if (Selection.activeGameObject == null)
                {
                    return;
                }

                MinCSRef.RunCode(Selection.activeGameObject, code);
            }

            model = (EModel) EditorGUILayout.EnumPopup(model);
            if (model == EModel.ShortModify)
            {
                DisplayModify();
            }
        }

        public void DisplayModify()
        {
            if (Selection.activeGameObject == null)
                return;

            BindingFlags bt = BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic |
                              BindingFlags.Public;
            var mbAry = Selection.activeGameObject.GetComponents<Component>();


            for (int i = 0; i < mbAry.Length; i++)
            {
                var objMono = mbAry[i];
                var type = mbAry[i].GetType();
                string tyName = mbAry[i].GetType().Name;
                string assemName = type.Assembly.GetName().Name;
                if (assemName.StartsWith("UnityEngine"))
                    continue;
                var fieldAry = type.GetFields(bt);
                List<FieldInfo> infoList = new List<FieldInfo>();
                List<MethodInfo> methodList = new List<MethodInfo>();
                var methodAry = type.GetMethods(bt);

                //分析字段
                for (int j = 0; j < fieldAry.Length; j++)
                {
                    FieldInfo fi = fieldAry[j];
                    var attr = fi.GetCustomAttributes();
                    if (fi.IsPublic)
                    {
                        bool result = false;
                        foreach (var item in attr)
                        {
                            if (item.GetType().Name == "HideInInspector")
                            {
                                result = true;
                                break;
                            }
                        }

                        if (!result)
                            continue;
                    }

                    infoList.Add(fi);
                }

                //分析方法
                for (int j = 0; j < methodAry.Length; j++)
                {
                    var m = methodAry[j];
                    if (m.Module.Assembly.GetName().Name.StartsWith("UnityEngine"))
                        continue;

                    if (filtrationMethod.Contains(m.Name))
                        continue;

                    var argsAry = m.GetParameters();
                    bool filtration = false;
                    for (int k = 0; k < argsAry.Length; k++)
                    {
                        var pt = argsAry[k].ParameterType;
                        if (pt.IsClass || pt.IsArray && pt.Name == "String")
                        {
                            filtration = true;
                            break;
                        }
                    }

                    if (filtration)
                        continue;

                    methodList.Add(methodAry[j]);
                }

                if (infoList.Count > 0 && methodList.Count > 0)
                    EditorGUILayout.LabelField("类:   " + tyName);

                ShowMethodPop(methodList, objMono);

                EditorGUILayout.LabelField("字段:   ");
                for (int j = 0; j < infoList.Count; j++)
                {
                    var fi = infoList[j];
                    var objVal = fi.GetValue(objMono);
                    Field(fi, objMono, objVal);
                }
            }
        }

        private void ShowMethodPop(List<MethodInfo> methodList, object mono)
        {
            if (methodList.Count > 0)
            {
              
                List<string> mList = new List<string>();
                for (int j = 0; j < methodList.Count; j++)
                {
                    mList.Add(methodList[j].Name);
                }

                if (selectMethod >= mList.Count)
                    selectMethod = 0;

                GUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("方法:",GUILayout.Width(150));
                selectMethod = EditorGUILayout.Popup(selectMethod, mList.ToArray());
                var mInfo = methodList[selectMethod];
                GUILayout.EndHorizontal();

                var args = mInfo.GetParameters();
                string[] argsList = new string[args.Length];
                for (int i = 0; i < args.Length; i++)
                {
                    argsList[i] = EditorGUILayout.TextField(args[i].Name, argsList[i]);
                }

                if (GUILayout.Button("执行", GUILayout.Height(30)))
                {
                    if (argsList.Length <= 0)
                        mInfo.Invoke(mono, null);
                    else
                    {
                        mInfo.Invoke(mono, null);
                    }
                }
            }
        }


        public void Field(FieldInfo fi, object objMono, object objVal)
        {
            if (fi.FieldType.Name == "Int32")
            {
                fi.SetValue(objMono, EditorGUILayout.IntField(fi.Name, (int) objVal));
            }
            else if (fi.FieldType.Name == "Boolean")
            {
                fi.SetValue(objMono, EditorGUILayout.Toggle(fi.Name, (bool) objVal));
            }
            else if (fi.FieldType.Name == "Single")
            {
                float val = Convert.ToSingle(EditorGUILayout.DoubleField(fi.Name, Convert.ToSingle(objVal)));
                fi.SetValue(objMono, val);
            }
            else if (fi.FieldType.Name == "Double")
            {
                fi.SetValue(objMono, EditorGUILayout.DoubleField(fi.Name, (double) objVal));
            }
            else if (fi.FieldType.Name == "Char")
            {
                fi.SetValue(objMono, EditorGUILayout.TextField(fi.Name, Convert.ToString(objVal)));
            }
            else if (fi.FieldType.Name == "String")
            {
                string s = null;
                if (objVal != null)
                    s = objVal.ToString();
                fi.SetValue(objMono, EditorGUILayout.TextField(fi.Name, s));
            }
        }


        public enum EModel
        {
            None,
            ShortModify
        }
    }
}